package com.example.supplychainbackend.service.Impl;

import com.example.supplychainbackend.controller.dto.blockchain.UploadInfo;
import com.example.supplychainbackend.controller.dto.logistic.DomesticLogisticDto;
import com.example.supplychainbackend.controller.dto.logistic.ForeignLogisticDto;
import com.example.supplychainbackend.dao.logistic.DomesticLogisticDao;
import com.example.supplychainbackend.dao.logistic.ForeignLogisticDao;
import com.example.supplychainbackend.entity.design.ECNEntity;
import com.example.supplychainbackend.entity.logistic.DomesticLogisticEntity;
import com.example.supplychainbackend.entity.logistic.ForeignLogisticEntity;
import com.example.supplychainbackend.mapper.LogisticMapper;
import com.example.supplychainbackend.service.BlockchainService;
import com.example.supplychainbackend.service.LogisticService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class LogisticServiceImpl implements LogisticService {
    private final DomesticLogisticDao domesticDao;
    private final ForeignLogisticDao foreignDao;
    private final LogisticMapper mapper;
    private final BlockchainService blockchainService;

    @Override
    public DomesticLogisticDto getDomesticLogistic(String trackingNumber) {
        DomesticLogisticEntity entity = domesticDao.findByTrackingNumber(trackingNumber);
        return mapper.toDomesticLogisticDto(entity);
    }

    @Override
    public DomesticLogisticDto updateDomesticLogistic(String trackingNumber, DomesticLogisticDto form) {
        if (!domesticDao.existsByTrackingNumber(trackingNumber)) {
            throw new RuntimeException("domestic logistic "+ trackingNumber+ " not exists");
        }
        DomesticLogisticEntity entity = mapper.toDomesticLogisticEntity(form);
        entity.setTrackingNumber(trackingNumber);
        return mapper.toDomesticLogisticDto(domesticDao.save(entity));
    }

    @Override
    public String createDomesticLogistic(DomesticLogisticDto form) {
        if (domesticDao.existsByTrackingNumber(form.getTrackingNumber())){
            throw new RuntimeException("id " + form.getTrackingNumber() + " already exists");
        }
        DomesticLogisticEntity entity = mapper.toDomesticLogisticEntity(form);
        entity.setOnChain(false);
        return domesticDao.save(entity).getTrackingNumber();
    }

    @Override
    public List<DomesticLogisticDto> getDomesticLogistics() {
        List<DomesticLogisticEntity> entities = domesticDao.findAll();
        return mapper.toDomesticLogisticDtoList(entities);
    }

    @Override
    public Long deleteDomesticLogistic(String trackingNumber) {
        return domesticDao.deleteByTrackingNumber(trackingNumber);
    }

    @Override
    public ForeignLogisticDto getForeignLogistic(String id) {
        ForeignLogisticEntity entity = foreignDao.findById(id).get();
        return mapper.toForeignLogisticDto(entity);
    }

    @Override
    public ForeignLogisticDto updateForeignLogistic(String id, ForeignLogisticDto form) {
        if (!foreignDao.existsById(id)){
            throw new RuntimeException("foreign logistic id " + id + " not exists");
        }
        ForeignLogisticEntity entity = mapper.toForeignLogisticEntity(form);
        entity.setId(id);
        entity = foreignDao.save(entity);
        return mapper.toForeignLogisticDto(entity);
    }

    @Override
    public String createForeignLogistic(ForeignLogisticDto form) {
        if (form.getId()!=null){
            throw new RuntimeException("id manual assignment not supported");
        }
        ForeignLogisticEntity entity = mapper.toForeignLogisticEntity(form);
        entity.setOnChain(false);
        return foreignDao.save(entity).getId();
    }

    @Override
    public List<ForeignLogisticDto> getAllForeignLogistics() {
        List<ForeignLogisticEntity> entities = foreignDao.findAll();
        return mapper.toForeignLogisticDtoList(entities);
    }

    @Override
    public Long deleteForeignLogistic(String id) {
        foreignDao.deleteById(id);
        return 1L;
    }

    @Override
    public UploadInfo uploadForeignLogistic(String id) {
        ForeignLogisticDto foreignLogistic = this.getForeignLogistic(id);
        if (null!=foreignLogistic){
            UploadInfo txInfo = blockchainService.uploadLogisticForeign(id, foreignLogistic.toString());
            foreignLogistic.setOnChain(true);
            foreignLogistic.setCommitTime(txInfo.getCommitTime());
            foreignLogistic.setTransactionId(txInfo.getTransactionId());
            foreignDao.save(mapper.toForeignLogisticEntity(foreignLogistic));
            return txInfo;
        }
        throw new RuntimeException("foreign logistic not found");
    }

    @Override
    public UploadInfo uploadDomesticLogistic(String id) {
        DomesticLogisticDto domesticLogistic = this.getDomesticLogistic(id);
        if (null!=domesticLogistic){
            UploadInfo txInfo = blockchainService.uploadLogisticDomestic(id, domesticLogistic.toString());
            domesticLogistic.setOnChain(true);
            domesticLogistic.setCommitTime(txInfo.getCommitTime());
            domesticLogistic.setTransactionId(txInfo.getTransactionId());
            domesticDao.save(mapper.toDomesticLogisticEntity(domesticLogistic));
            return txInfo;
        }
        throw new RuntimeException("domestic logistic not found");
    }
}
